package pers.jphoebe.quartz.exception;

import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import pers.jphoebe.quartz.entity.response.ErrorCode;
import pers.jphoebe.quartz.entity.response.ResponseData;
import pers.jphoebe.quartz.utils.Logger;
import pers.jphoebe.quartz.utils.ResponseDataUtils;

import javax.servlet.http.HttpServletRequest;

import static org.springframework.http.HttpStatus.*;

/**
 * Created by 蒋时华 on 2017/10/31.
 * request请求异常处理
 */
@ControllerAdvice
public class RequestExceptionHandler extends ResponseEntityExceptionHandler {

    private Logger logger = Logger.getLogger(this.getClass());

    @Override
    protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return new ResponseEntity<Object>(ResponseDataUtils.error(ErrorCode.ERROR_CODE), NOT_EXTENDED);
    }

    /**
     * 处理@RequestParam异常, 即参数不足
     */
    @Override
    protected ResponseEntity<Object> handleMissingServletRequestParameter(MissingServletRequestParameterException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return new ResponseEntity<Object>(ResponseDataUtils.error(ErrorCode.ERROR_MISS_PARAMTER), status);
    }
    /**
     * 处理@PathVariable异常, 即参数不足
     */
    @Override
    protected ResponseEntity<Object> handleMissingPathVariable(MissingPathVariableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return new ResponseEntity<Object>(ResponseDataUtils.error(ErrorCode.ERROR_MISS_PARAMTER), status);
    }

    /**
     * 处理参数类型转换失败
     * @param request
     * @return
     */
    @Override
    protected ResponseEntity<Object> handleTypeMismatch(TypeMismatchException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return new ResponseEntity<Object>(ResponseDataUtils.error(ErrorCode.ERROR_PARAMTER_MATCH), status);
    }

    /**
     * 媒体类型不支持异常
     * @param ex
     * @param headers
     * @param status
     * @param request
     * @return
     */
    @Override
    protected ResponseEntity<Object> handleHttpMediaTypeNotSupported(HttpMediaTypeNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return new ResponseEntity<Object>(ResponseDataUtils.error(ErrorCode.ERROR_NOT_SUPPORT_MEDIA_TYPE), UNSUPPORTED_MEDIA_TYPE);
    }

    /**
     * 媒体类型不可接受
     * @param ex
     * @param headers
     * @param status
     * @param request
     * @return
     */
    @Override
    protected ResponseEntity<Object> handleHttpMediaTypeNotAcceptable(HttpMediaTypeNotAcceptableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return new ResponseEntity<Object>(ResponseDataUtils.error(ErrorCode.ERROR_NOT_ACCEPTED_MEDIA_TYPE), status);
    }

    /**
     * 请求超时
     * @return
     */
    @Override
    protected ResponseEntity<Object> handleAsyncRequestTimeoutException(AsyncRequestTimeoutException ex, HttpHeaders headers, HttpStatus status, WebRequest webRequest) {
        return new ResponseEntity<Object>(ResponseDataUtils.error(ErrorCode.ERROR_TIMEOUT), REQUEST_TIMEOUT);
    }

    /**
     * 请求方法类型错误异常
     * @param ex
     * @param headers
     * @param status
     * @param request
     * @return
     */
    @Override
    protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return new ResponseEntity<Object>(ResponseDataUtils.error(ErrorCode.ERROR_METHOD_NOT_ALLOWED), METHOD_NOT_ALLOWED);
    }

    /**
     * @RequestBody 参数验证异常
     * @param ex
     * @param headers
     * @param status
     * @param request
     * @return
     */
    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return new ResponseEntity<Object>(ResponseDataUtils.error(ErrorCode.ERROR_REQUEST_BODY), status);
    }

    /**
     * 文件上传异常
     * @param ex
     * @param headers
     * @param status
     * @param request
     * @return
     */
    @Override
    protected ResponseEntity<Object> handleConversionNotSupported(ConversionNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        return new ResponseEntity<Object>(ResponseDataUtils.error(ErrorCode.ERROR_UPLOAD_FILE), status);
    }

    /**
     * 进入到实际逻辑执行了，抛出的异常
     * @param request
     * @param e
     * @return
     * @throws Exception
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResponseData jsonHandler(HttpServletRequest request, Exception e) throws Exception {
        ResponseData r = new ResponseData();
        r.setCodeAndMessage(ErrorCode.ERROR_CODE);
        r.setData(e.getMessage());

        logger.fullLog(e, request);

        return r;
    }

}
